#ifndef _VECTOR_H_
#define _VECTOR_H_
#include <functional>
#include <assert.h>
template <typename T>
class vector {
private:
	class Iterator {
	public:
		Iterator(T* m_point) :m_point(m_point) {
			
		}
		Iterator& operator++() {
			++m_point;
			return *this;
		}
		Iterator& operator--() {
			--m_point;
			return *this;
		}
		Iterator& operator++(int) {
			Iterator Iter = *this;
			++(*this);
			return Iter;
		}
		Iterator operator+(const int diff) {
			return Iterator{ m_point + diff };
		}
		Iterator operator-(const int diff) {
			return Iterator{ m_point - diff };
		}
		const Iterator operator+(const int diff)const{
			return Iterator{ m_point + diff };
		}
		const Iterator operator-(const int diff)const {
			return Iterator{ m_point - diff };
		}
		ptrdiff_t operator+(const Iterator& other) {
			return m_point + other.m_point;
		}
		ptrdiff_t operator-(const Iterator& other) {
			return m_point - other.m_point;
		}
		const ptrdiff_t operator+(const Iterator& other)const {
			return m_point + other.m_point;
		}
		const ptrdiff_t operator-(const Iterator& other)const {
			return m_point - other.m_point;
		}
		bool operator==(const Iterator& other) {
			return m_point == other.m_point;
		}
		bool operator!=(const Iterator& other) {
			return m_point != other.m_point;
		}
		T &operator*() {
			assert(m_point);
			return *m_point;
		}
		const T& operator*()const {
			assert(m_point);
			return *m_point;
		}
	private:
		T* m_point;
	};
public:
	vector() :_data(nullptr), _capacity(2), cnt(0) {
		malloc();
	}
	vector(vector& other) :cnt(other.cnt) {
		copy(other);
	}
	vector(vector&& other) :_capacity(std::forward<size_t>(other._capacity)), cnt(std::forward<size_t>(other.cnt)) {
		movecopy(other);
	}
	vector& operator=(vector& other) {
		if (this != &other) {
			_capacity = other._capacity;
			cnt = other.cnt;
			copy(other);
		}
		return *this;
	}
	vector& operator=(vector&& other) {
		if (this != &other) {
			cnt = other.cnt;
			movecopy(other);
		}
		return *this;
	}
	
	~vector() {
		_clear();
	}
	
	Iterator begin() {
		return Iterator{ _data };
	}
	const Iterator begin()const {
		return Iterator{ _data };
	}
	
	const Iterator cbegin()const {
		return begin();
	}
	
	Iterator rbegin() {
		return end() - 1;
	}
	const Iterator rbegin()const {
		return end() - 1;
	}
	
	const Iterator rcbegin()const {
		return end() - 1;
	}
	
	Iterator end() {
		return Iterator{ _data + cnt };
	}
	const Iterator end()const {
		return Iterator{ _data + cnt };
	}
	
	const Iterator cend()const {
		return end();
	}
	
	Iterator rend() {
		return begin() - 1;
	}
	const Iterator rend()const {
		return begin() - 1;
	}
	
	const Iterator rcend()const {
		return begin() - 1;
	}
	
	size_t size() {
		return cnt;
	}
	
	size_t capacity() {
		return _capacity;
	}
	
	void push_back(T& value) {
		if (cnt >= _capacity) {
			Remalloc();
		}
		new(&_data[cnt])T(value);
		++cnt;
		
	}
	void push_back(T&& value) {
		if (cnt >= _capacity) {
			Remalloc();
		}
		new(&_data[cnt])T(std::forward<T>(value));
		++cnt;
	}
	
	void pop_back() {
		if (cnt > 0) {
			--cnt;
			_data[cnt].~T();
		}
	}
	
	T& back() {
		size_t end = cnt;
		assert(cnt > 0);
		return _data[end - 1];
	}
	const T& back()const {
		size_t end = cnt;
		assert(cnt > 0);
		return _data[end - 1];
	}
	
	void clear() {
		size_t end = cnt;
		for (int i = 0; i < end; ++i) {
			pop_back();
		}
	}
	
	const T& at(const size_t index)const {
		assert(index <= cnt - 1);
		return _data[index];
	}
	T& at(const size_t index) {
		assert(index <= cnt - 1);
		return _data[index];
	}
	
	bool empty()const {
		return cnt > 0 ? true : false;
	}
	
	const T& front()const {
		assert(cnt > 0);
		return _data[0];
	}
	T& front() {
		assert(cnt > 0);
		return _data[0];
	}
	
	template<typename ...Args>
	void emplace_back(Args&&...args) {
		new(&_data[cnt])T(std::forward<Args>(args)...);
		++cnt;
	}
	
	template<typename ...Args>
	void emplace(const Iterator Where, Args&&...args) {
		const ptrdiff_t pos = Where - cbegin();
		assert(pos >= 0 && pos <= cnt);
		resize(cnt + 1);
		if (pos == cnt - 1) {
			new(&_data[pos])T(std::forward<Args>(args)...);
		}
		else {
			for (int i = cnt - 2; i >= pos; --i) {
				new(&_data[i + 1])T(_data[i]);
			}
			new(&_data[pos])T(std::forward<Args>(args)...);
		}
	}
	
	Iterator erase(const Iterator Where) {
		const ptrdiff_t pos = Where - cbegin();
		assert(pos >= 0 && pos <= cnt - 1);
		for (ptrdiff_t i = pos; i < cnt - 1; ++i) {
			new(&_data[i])T(_data[i + 1]);
		}
		pop_back();
		return Where + 1;
	}
	Iterator erase(const Iterator First, const Iterator End) {
		const ptrdiff_t startpos = First - cbegin();
		const ptrdiff_t endpos = End - cbegin();
		assert(startpos <= endpos && startpos >= 0 && endpos <= cnt);
		if (endpos == startpos) {
			return begin();
		}
		ptrdiff_t start = startpos;
		for (ptrdiff_t i = endpos; i < cnt; ++i) {
			new(&_data[start])T(_data[i]);
			++start;
		}
		const ptrdiff_t diff = endpos - startpos;
		for (size_t i = 0; i < diff; ++i) {
			pop_back();
		}
		return First + diff;
	}
	
	const T* data()const {
		return _data;
	}
	T* data() {
		return _data;
	}
	
	void resize(const size_t new_cnt) {
		Remalloc(new_cnt);
	}
	void resize(const size_t new_cnt, const T& val) {
		Remalloc(new_cnt, val);
	}
	
	void reserve(const size_t new_capacity) {
		T* new_data = nullptr; 
		new_data = (T*)::operator new(sizeof(T) * _capacity);
		for (int i = 0; i < cnt; ++i) {
			new(&new_data[i])T(_data[i]);
		}
		if (_data) {
			::operator delete(_data, sizeof(T) * _capacity);
			_data = nullptr;
		}
		_data = (T*)::operator new(sizeof(T) * new_capacity);
		for (int i = 0; i < cnt; ++i) {
			new(&_data[i])T(new_data[i]);
		}
		if (new_data) {
			::operator delete(new_data, sizeof(T) * _capacity);
			new_data = nullptr;
		}
		_capacity = new_capacity;
	}
	
	T& operator[](size_t &index) {
		assert(0 <= index && index <= cnt - 1);
		return	_data[index];
	}
	const T& operator[](size_t&& index) const{
		assert(0 <= index && index <= cnt - 1);
		return	_data[index];
	}
private:
	
	void malloc() {
		if (!_data) {
			_data = (T*)::operator new(sizeof(T) * _capacity);
		}
	}
	
	void Remalloc() {
		size_t old_capacity = _capacity;
		_capacity = _capacity << 1;
		size_t _cnt = cnt;
		if (_cnt >= _capacity) {
			_capacity = _cnt;
		}
		T* new_data = (T*)::operator new(sizeof(T) * _capacity);
		for (int i = 0; i < _cnt; ++i) {
			new(&new_data[i])T(_data[i]);
		}
		::operator delete(_data, sizeof(T) * old_capacity);
		_data = nullptr;
		_data = new_data;
	}
	void Remalloc(const size_t new_cnt, const T &val = 0) {
		size_t old_capacity = _capacity;
		if (new_cnt > cnt) {
			if (new_cnt >= _capacity) {
				_capacity = new_cnt;
				T* new_data = (T*)::operator new(sizeof(T) * _capacity);
				for (int i = 0; i < cnt; ++i) {
					new(&new_data[i])T(_data[i]);
				}
				::operator delete(_data, sizeof(T) * old_capacity);
				_data = nullptr;
				_data = new_data;
			}
			for (int i = cnt; i < new_cnt; ++i) {
				new(&_data[i])T(val);
			}
		}
		else {
			for (int i = new_cnt; i < cnt; ++i) {
				new(&_data[i])T(val);
			}
		}
		cnt = new_cnt;
	}
	
	void _clear() {
		if (_data) {
			::operator delete(_data, sizeof(T) * _capacity);
			_data = nullptr;
		}
	}
	
	void copy(vector<T> &other) {
		if (_data) {
			::operator delete(_data, sizeof(T) * _capacity);
			_data = nullptr;
		}
		_capacity = other._capacity;
		_data = (T*)::operator new(sizeof(T) * _capacity);
		for (int i = 0; i < cnt; ++i) {
			new(&_data[i])T(other._data[i]);
		}
	}
	
	void movecopy(vector<T>& other) {
		copy(other);
		other.cnt = 0;
		if (other._data) {
			::operator delete(other._data, sizeof(T) * other._capacity);
			other._data = nullptr;
		}
		other._capacity = 2;
		if (!other._data) {
			other._data = (T*)::operator new(sizeof(T) * other._capacity);
		}
	}
private:
	T* _data;
	size_t _capacity;
	size_t cnt;
};
#endif // !_VECTOR_H_

